package com.szsh.aiot.hsm.dao;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.szsh.aiot.common.utils.EncryptUtil;
import com.szsh.aiot.common.utils.StringUtils;
import com.szsh.aiot.hsm.domain.IFlowDevice;
import com.szsh.aiot.hsm.domain.IUserDevice;
import com.szsh.aiot.hsm.dto.mkreport.MKReportRequest;
import com.szsh.aiot.hsm.dto.mkreport.MKReportResponse;
import com.szsh.aiot.hsm.dto.mkreport.Macs;
import com.szsh.aiot.hsm.enums.DeviceType;
import com.szsh.aiot.hsm.properties.MkProperties;
import com.szsh.aiot.hsm.utils.AESUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections4.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 迈科设备上报接口
 */
@Component
public class MkDao {
    private static final Logger LOGGER = LoggerFactory.getLogger(MkDao.class);

    @Value("${hsm.mkreport.endpoint}")
    private String url;

    @Value("${hsm.mkreport.partner-key}")
    private String partnerKey;

    @Value("${hsm.mkreport.partner-id}")
    private String partnerID;


    private final MkProperties mkProperties;

    private final RestTemplate restTemplate;

    private final Gson gson;

    public MkDao(MkProperties mkProperties, RestTemplate restTemplate, Gson gson) {
        this.mkProperties = mkProperties;
        this.restTemplate = restTemplate;
        this.gson = gson;
    }

    /**
     * 获取调用接口的type
     * @param userDevice 用户设备表
     * @return null:失败;<br>
     *         camera/tycamera/other
     */
    public String getType(IUserDevice userDevice) {
        if (null == userDevice) {
            return "other";
        }
        String showName = userDevice.getShowName();
        if (StringUtils.isBlank(showName)) {
            return "other";
        }
        String type = null;
        if (showName.contains("摄像")) {
            type = "camera";
        }
        if (showName.contains("天翼摄像") || userDevice.getDeviceType() == DeviceType.CAMERA.getVal()) {
            // 或者设备表明确表示是天翼摄像头
            type = "tycamera";
        }
        if (showName.contains("音箱") || showName.contains("音响") || showName.contains("门铃")) {
            type = "other";
        }
        return type;
    }

    /**
     * 获取调用接口的type
     * @param  flowDevice 流量告警
     * @param userDevice  用户设备表
     * @return null:失败;<br>
     *         camera/tycamera/other
     */
    public String getType(IFlowDevice flowDevice, IUserDevice userDevice) {
        String type = "other";
        if (Objects.equals(DeviceType.CAMERA.getVal(), flowDevice.getDeviceType())) {
            if (StringUtils.isNotBlank(userDevice.getShowName())) {
                if (userDevice.getShowName().contains("摄像")) {
                    type = "camera";
                }
                if (userDevice.getShowName().contains("天翼摄像")) {
                    type = "tycamera";
                }
            }
        }
        return type;
    }

    /**
     * 添加 mac订阅接口信息一览
     * @param mac   MAC地址
     * @param type  camera/tycamera/other
     * @return true:添加成功;<br>false:添加失败
     */
    public boolean addReport(String mac, String type) {
        if (StringUtils.isBlank(mac) || StringUtils.isBlank(type)) {
            return false;
        }
        Map<String, String> batchMap = new HashMap<>();
        batchMap.put(mac, type);
        return batchAddReport(batchMap);
    }

    /**
     * 批量添加 mac订阅接口信息一览
     * @param batchMap 批量数据,数据格式<br>
     *                 key: MAC地址<br>
     *                 value: type(camera/tycamera/other)
     * @return true:添加成功;<br>false:添加失败
     */
    public boolean batchAddReport(Map<String, String> batchMap) {
        if (MapUtils.isEmpty(batchMap)) {
            return false;
        }
        return batchReport(batchMap, "add");
    }

    /**
     * 删除 mac订阅接口信息一览
     * @param mac   MAC地址
     * @param type  camera/tycamera/other
     * @return true:删除成功;<br>false:删除失败
     */
    public boolean deleteReport(String mac, String type) {
        if (StringUtils.isBlank(mac) || StringUtils.isBlank(type)) {
            return false;
        }
        Map<String, String> batchMap = new HashMap<>();
        batchMap.put(mac, type);
        return batchDeleteReport(batchMap);
    }

    /**
     * 批量删除 mac订阅接口信息一览
     * @param batchMap 批量数据,数据格式<br>
     *                 key: MAC地址<br>
     *                 value: type(camera/tycamera/other)
     * @return true:添加成功;<br>false:添加失败
     */
    public boolean batchDeleteReport(Map<String, String> batchMap) {
        if (MapUtils.isEmpty(batchMap)) {
            return false;
        }
        return batchReport(batchMap, "delete");
    }

    /**
     * 添加/删除 mac订阅接口信息一览
     * @param mac      设备MAC
     * @param type     camera/tycamera/other
     * @param action   操作类型<br>
     *                 add : 添加<br>
     *                 delete : 删除
     * @return true : 成功<br>false : 失败
     */
    public boolean report(String mac, String type, String action) {
        if (StringUtils.isBlank(mac)) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("mac为空");
            }
            return false;
        }
        if (StringUtils.isBlank(type)) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("type为空");
            }
            return false;
        }
        if (!(Objects.equals("add", action) || Objects.equals("delete", action))) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("action错误.action:[{}]", action);
            }
            return false;
        }

        Map<String, String> batchMap = new HashMap<>();
        batchMap.put(mac, type);
        return batchReport(batchMap, action);
    }

    /**
     * 批量 添加/删除 mac订阅接口信息一览
     * @param batchMap 批量数据,数据格式<br>
     *                 key: MAC地址<br>
     *                 value: type(camera/tycamera/other)
     * @param action   操作类型<br>
     *                 add : 添加<br>
     *                 delete : 删除
     * @return true:添加成功;<br>false:添加失败
     */
    public boolean batchReport(Map<String, String> batchMap, String action) {
        if (MapUtils.isEmpty(batchMap)) {
            return false;
        }

        if (!(Objects.equals("add", action) || Objects.equals("delete", action))) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("action错误.action:[{}]", action);
            }
            return false;
        }

        JsonObject parasJsonObject = new JsonObject();

        batchMap.forEach((mac, type)->{
            JsonObject operatorJsonObject = new JsonObject();

            operatorJsonObject.addProperty("action", action);
            operatorJsonObject.addProperty("type", type);

            parasJsonObject.add(mac, operatorJsonObject);
        });

        // 上报
        String resultStr = report(parasJsonObject);

        if (StringUtils.isBlank(resultStr)) {
            return false;
        }
        JsonObject returnJsonObject;
        try {
            returnJsonObject = gson.fromJson(resultStr, JsonObject.class);
        } catch (Exception e) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("系统异常", e);
            }
            return false;
        }
        if (null == returnJsonObject) {
            return false;
        }

        JsonElement jsonElement = returnJsonObject.get("code");
        if (!jsonElement.isJsonPrimitive()) {
            return false;
        }

        return Objects.equals(0, jsonElement.getAsInt());
    }

    /**
     * 添加/删除 mac订阅接口信息一览
     * @param parasJsonObject 参数格式:<br>
     *                        <pre>{@code
     *                        {
     *                          "MAC1":{
     *                              "brand":"可选参数",
     *                              "model":"可选参数",
     *                              "action":"add/delete",
     *                              "type":"camera/tycamera/other"
     *                          },
     *                          "MAC2":{
     *                              "brand":"可选参数",
     *                              "model":"可选参数",
     *                              "action":"add/delete",
     *                              "type":"camera/tycamera/other"
     *                          }
     *                        }
     *                        }</pre>
     * @return null:调用失败
     */
    private String report(JsonObject parasJsonObject) {
        return post(mkProperties.getReportUrl(), parasJsonObject);
    }

    /**
     * 执行请求
     * @param url 请求地址
     * @param parasJsonObject 参数格式:<br>
     *                        <pre>{@code
     *                        {
     *                          "MAC1":{
     *                              "brand":"可选参数",
     *                              "model":"可选参数",
     *                              "action":"add/delete",
     *                              "type":"camera/tycamera/other"
     *                          },
     *                          "MAC2":{
     *                              "brand":"可选参数",
     *                              "model":"可选参数",
     *                              "action":"add/delete",
     *                              "type":"camera/tycamera/other"
     *                          }
     *                        }
     *                        }</pre>
     * @return null:调用失败
     */
    private String post(String url, JsonObject parasJsonObject) {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("迈科上报接口,url:[{}],parasJsonObject:[{}]", url, parasJsonObject);
        }

        long timestamp = System.currentTimeMillis();
        String encryptStr;
        try {
            String iv = Base64.encodeBase64String((mkProperties.getReportAppId() + timestamp).getBytes(StandardCharsets.UTF_8));
            encryptStr = EncryptUtil.encryptAESBase64String(parasJsonObject.toString(), mkProperties.getReportAppKey(), iv);
        } catch (Exception e) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("迈科上报接口,加密失败", e);
            }
            return null;
        }

        // 请求参数
        JsonObject requestJsonObject = new JsonObject();

        requestJsonObject.addProperty("macs", encryptStr);
        requestJsonObject.addProperty("timestamp", timestamp);

        // 发送请求
        String resultStr;
        try {
            resultStr = restTemplate.postForObject(url, requestJsonObject, String.class);
        } catch (Exception e) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("迈科上报接口,调用接口异常", e);
            }
            return null;
        }
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("迈科上报接口,返回结果:[{}]", resultStr);
        }

        return resultStr;
    }

    public MKReportResponse mkReport(String mac, String type, String action) {
        MKReportResponse response = new MKReportResponse();
        try{
            MKReportRequest req = new MKReportRequest();
            Macs macinfo = new Macs();
            macinfo.setType(type);
            macinfo.setAction(action);
            Map<String, Macs> map = new HashMap<>();
            map.put(mac, macinfo);
            String macs = gson.toJson(map);
            Long tamp = System.currentTimeMillis();
            String iv = partnerID + tamp;
            String encryptResultStr = AESUtil.encrypt(macs, partnerKey, iv);
            req.setMacs(encryptResultStr);
            req.setTimestamp(tamp);
            LOGGER.info("MKReport Req[{}]", req.toString());
            String rsp = restTemplate.postForObject(url, req, String.class);
            LOGGER.info("MKReport Rsp[{}]", rsp);
            response= gson.fromJson(rsp,MKReportResponse.class);
        }catch (Exception e){
            response.setCode(-1);
            LOGGER.error("调用迈科上报接口异常{}",e);
        }
        return response;
    }
}
